#pragma once
#include <iostream>

template <typename Object, typename ClassType>
inline bool instanceof (Object & object)
{
	try
	{
		[[maybe_unused]] ClassType &newObject = dynamic_cast<ClassType &>(object);
		return true;
	}
	catch (const std::bad_cast &e)
	{
		return false;
	}
}

template <typename Object, typename ClassType>
inline bool instanceof (Object * object)
{
	[[maybe_unused]] ClassType *newObject = dynamic_cast<ClassType *>(object);
	return newObject != nullptr;
}

template <typename Object, typename ClassType>
inline bool instanceof (std::shared_ptr<Object> object)
{
	[[maybe_unused]] std::shared_ptr<ClassType> newObject = std::dynamic_pointer_cast<ClassType>(object);
	return newObject != nullptr;
}

// class Base
// {
// public:
//     virtual void print() const { std::cout << "Base\n"; }
//     virtual ~Base() {}
// };

// class Derived: public Base
// {
// public:
//     void print() const override { std::cout << "Derived\n"; }
// };

// class NonVirtualClass {};
// class VirtualClass {public: virtual ~VirtualClass() {} };

// int main()
// {
// 	Derived derived;
// 	Base& base = derived;
// 	Base* pBase = new Derived;

// 	[[maybe_unused]]
// 	NonVirtualClass nonVirtualObject;
// 	VirtualClass virtualObject;

// 	std::cout << std::boolalpha << "base    instanceof Base: " << instanceof<Base, Base>(base) << '\n';
// 	std::cout << std::boolalpha << "derived instanceof Base: " << instanceof<Base, Derived>(base) << '\n';
// 	std::cout << std::boolalpha << "pBase   instanceof Base: " << instanceof<Base, Derived>(pBase) << '\n';
// 	std::cout << std::boolalpha << "pBase   instanceof NonVirtualClass: " << instanceof<Base, NonVirtualClass>(pBase) << '\n';
// 	std::cout << std::boolalpha << "pBase   instanceof VirtualClass: " << instanceof<Base, VirtualClass>(pBase) << '\n';

// //	std::cout << std::boolalpha << "nonVirtualObject instanceof Base: " << instanceof<NonVirtualClass, Base>(nonVirtualObject) << '\n';
// 	// error: source type is not polymorphic.
// 	std::cout << std::boolalpha << "virtualObject instanceof Base: " << instanceof<VirtualClass, Base>(virtualObject) << '\n';
// 	std::cout << std::boolalpha << "virtualObject instanceof VirtualClass: " << instanceof<VirtualClass, VirtualClass>(virtualObject) << '\n';
// 	delete pBase;

// 	return 0;
// }